Original pascal source code in "Floating.p" by F. Pottier (see his own comments below), Translated into C because I couldn't find the original C code mentioned in his comments below. I have edited the file several times, and I have also included a header file. The changes have been documented at the top of "floating.c"
Information:
"floating.c" - easily manage floating windoids in your application.
Originally based on a set of C routines written by Patrick Doane (America OnLine : Patrick5). Later translated into pascal by F. Pottier (pottier@clipper.ens.fr) Thanks go to these two, and also to Troy Gaul for placing his Infinity Windoid in the public domain.
This code is placed in the public domain. It may be used by anybody, for any purposes. It would be kind to give credits to me as well as to the aforementioned people, though. If you experience any problems, or have ideas for enhancements, tell me about it. I can't guarantee I'll spend much time on it, since I'm only a student and not a professional programmer, but I'll definitely look into it.
Comments on Usage:
The Window Manager doesn't know about floating windows. To obtain floating windows in a program, one has to handle them 'by hand', which means calling low-level Window Manager routines to place the windows in their correct positions after each event.
The frequently used, and now to be avoided, Window Manager routines are:
SelectWindow
CloseWindow
HideWindow
ShowWindow
DisposeWindow
DragWindow
Those routines don't know about floating windows, so calling them may mix the floating windows among normal windows.
You also have to be careful with GetNewWindow. You can't call GetNewWindow(ID, wStorage, Pointer(-1)) because that
would put the new window in the front. Rather, we call GetNewWindow(ID, wStorage, nil) which places the window in the
back, and then call our home-made routine, SelectTheWindow.
At every point in the program, we maintain three global variables : topFloat, bottomFloat and topWindow.
topFloat holds the top floating window, nil if there is none. Same thing for bottomFloat with the bottom floating window,
and for topWindow with the top regular window. These three global variables, along with the Window Manager's window
list, are enough to handle the behavior of our windows.
Hidden windows are placed behind all others, so they don't count when determining those variables' values.
In order to distinguish between floating windows and regular ones, we choose a different windowKind for the former.
To make hiliting and unhiliting floating windows simpler, I chose to use a WDEF that always draws windoids in a hilited
state (e.g. Infinity Windoid with the Always Hilite option). This way, I don't have to worry at all about it.
A final remark about modeless dialogs : modeless dialogs and floating windows don't go well together. The Dialog Manager
is confused by floating windows. IsDialogEvent and DialogSelect don't work because they use FrontWindow to find the dialog.
It is easy to rewrite a modified version of isDialogEvent. It is already trickier for DialogSelect. Maybe it would be simpler
to use windows with controls instead of modeless dialogs. Or maybe it's possible to have DialogSelect and isDialogEvent
work by patching FrontWindow? If somebody comes up with a good idea on this topic, please tell me about it.
Usage (in brief):
- Call InitFloats once before opening any windows.
- To create a new window, call GetNewWindow(id, storage, nil). Then call SelectTheWindow if it's a regular window,
otherwise call MakeFloat.
- To determine whether a given window is a floating one, call isFloating(whichWindow)
- Instead of SelectWindow[and ShowWindow], HideWindow, DisposeWindow, DragWindow, use SelectTheWindow, HideTheWindow,
DisposeTheWindow and DragTheWindow.
- Upon a receiving a suspend event, you may call HideFloats(), and ShowFloats() when receiving a resume event. However, be
aware that these routines have been tested to be buggy on my machine. Instead, I recommend treating floats as normal windows
when showing them or hidin them - use HideTheWindow(). However, keep a global flag which tells which windows should be
shown. This is useful for activate events so even though the user closes a few floats, the program will not automatically show
every one of them again.
- Instead of calling FrontWindow(), you can read the values of the variables topFloat and topWindow. They should be up-to-date
at any point in the program.
More Info:
Hoping to someday become a masterful Mac Programmer, I've already started on a really promising application frame. If anybody is interested, give me a buzz (jdeweese@sytex.net). It's currently at version 1.0a5 in native PowerPC code. It is easily portable to 68K, too.